package com.ichir.projects.uiflow.internal.decorators;


import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import com.ichir.projects.uiflow.ApplicationContext;
import com.ichir.projects.uiflow.definition.FlowType;
import com.ichir.projects.uiflow.definition.IUiWithProgress;
import com.ichir.projects.uiflow.events.IUiPartListener;
import com.ichir.projects.uiflow.events.UiEvent;
import com.ichir.projects.uiflow.internal.executors.ExecutorsRegistry;
import com.ichir.projects.uiflow.ui.api.IUiAction;
import com.ichir.projects.uiflow.ui.api.IUiPart;
import com.ichir.projects.uiflow.ui.api.IUiView;

/**
 * UiAtion decorator for Event listeners.
 * 
 * @author mahieddine
 * @since 1.0.0
 */
public class UiActionDecorator implements IUiAction, IUiWithProgress {

	private IUiPart progress;

	private IUiAction action;

	private List<WeakReference<IUiPartListener>> listeners = new ArrayList<WeakReference<IUiPartListener>>();

	/**
	 * Add an event listener to handled class.
	 * @param listener listener to add.
	 */
	public final void addHandledListener(IUiPartListener listener) {
		if (listeners.contains(listener)) {
			return;
		}
		listeners.add(new WeakReference<IUiPartListener>(listener));
	}

	/**
	 * Remove an event listener.
	 * @param listener listener to remove
	 */
	public final void removeHandledListener(IUiPartListener listener) {
		if (! listeners.contains(listener)) {
			return;
		}
		listeners.remove(listener);
	}

	/**
	 * Fire an event
	 * @param eventName event Id
	 * @param eventType event type
	 * @param attributes event context attributes
	 * @throws Exception 
	 */
	public final void fireEvent(IUiPart source, UiEvent event) {
		for (WeakReference<IUiPartListener> reference : listeners) {
			reference.get().onEvent(source, event.getEventId(), event.getAttributes());
		}
	}

	@Override
	public UiEvent execute(final ApplicationContext context,
			final Map<String, Object> attributes) {
		if (progress != null) {
			ExecutorsRegistry.execute(progress, FlowType.VIEW, context, attributes);
		}
		UiEvent ret = action.execute(context, attributes);
		if (progress != null) {
			((IUiView) progress).disposeView(context, attributes);
		}
		fireEvent(action, ret);
		return ret;
	}

	public IUiAction getAction() {
		return action;
	}

	public void setAction(IUiAction action) {
		this.action = action;
	}

	@Override
	public IUiPart getProgress() {
		return progress;
	}

	public void setProgress(IUiPart progress) {
		this.progress = progress;
	}
}
